terraform-provider-eksctlで既存のVPC上にEKSクラスターを作成してみた
eksctlでのEKSクラスター作成は、デフォルトではクラスターが稼働するVPCも併せて作成してくれます。が、既存のVPC上にクラスターを作成することもできます。今回はこの構成をterraform-provider-eksctlでやってみます。
※ terraform-provider-eksctlについてご存じない方は、まずは以下ブログをどうぞ。
VPCの作成
VPC関連のリソースは色々あって一つずつプロビジョニングするのが煩雑なので、以下公式モジュールを利用してラクします。
terraform { required_version = "= 0.14.7" required_providers { aws = { source = "hashicorp/aws" version = "3.30.0" } } } provider "aws" { region = "ap-northeast-1" }
data "aws_availability_zones" "available" { state = "available" } module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "2.77.0" name = "canary-test-vpc" cidr = "10.0.0.0/16" azs = data.aws_availability_zones.available.names private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"] enable_nat_gateway = true }
terraform init
してterraform apply
すると、以下リソースが作成されました。楽ちんですね。
$ terraform state list data.aws_availability_zones.available module.vpc.aws_eip.nat[0] module.vpc.aws_eip.nat[1] module.vpc.aws_eip.nat[2] module.vpc.aws_internet_gateway.this[0] module.vpc.aws_nat_gateway.this[0] module.vpc.aws_nat_gateway.this[1] module.vpc.aws_nat_gateway.this[2] module.vpc.aws_route.private_nat_gateway[0] module.vpc.aws_route.private_nat_gateway[1] module.vpc.aws_route.private_nat_gateway[2] module.vpc.aws_route.public_internet_gateway[0] module.vpc.aws_route_table.private[0] module.vpc.aws_route_table.private[1] module.vpc.aws_route_table.private[2] module.vpc.aws_route_table.public[0] module.vpc.aws_route_table_association.private[0] module.vpc.aws_route_table_association.private[1] module.vpc.aws_route_table_association.private[2] module.vpc.aws_route_table_association.public[0] module.vpc.aws_route_table_association.public[1] module.vpc.aws_route_table_association.public[2] module.vpc.aws_subnet.private[0] module.vpc.aws_subnet.private[1] module.vpc.aws_subnet.private[2] module.vpc.aws_subnet.public[0] module.vpc.aws_subnet.public[1] module.vpc.aws_subnet.public[2] module.vpc.aws_vpc.this[0]
上記VPCを使ってEKSクラスターを作成
eksctlを使う部分は、今後(=次回以降のブログで)複数回使いたいのでmoduleにします。
data "aws_region" "current" {} module "blue" { source = "./modules/k8s_cluster" cluster_name = "blue" region = data.aws_region.current.name k8s_version = "1.19" vpc_id = module.vpc.vpc_id private_subnet_ids = module.vpc.private_subnets public_subnet_ids = module.vpc.public_subnets }
モジュール用のファイル群を用意します。
$ tree ./ ./ ├── blue.tf ├── main.tf ├── modules │ └── k8s_cluster │ ├── eksctl.tf │ ├── providers.tf │ ├── target_group.tf │ ├── variables.tf │ └── yaml │ └── eksctl-config.yaml └── vpc.tf
provider.tf
には、terraform-provider-eksctlを使うことだけ定義しています。
terraform { required_providers { eksctl = { source = "mumoshu/eksctl" version = "0.15.1" } } } provider "eksctl" {}
variables.tf
では変数を定義します。vpc_id
以降の3変数は先程のVPCモジュールから参照する想定です。この公式VPCモジュール、output値がものすごくたくさんあるので、こういった感じで他で参照するような要件もほとんど対応できるのではないかと思います。
variable "cluster_name" { type = string } variable "region" { type = string } variable "k8s_version" { type = string } variable "vpc_id" { type = string } variable "private_subnet_ids" { type = list(string) } variable "public_subnet_ids" { type = list(string) }
eksctl.tf
のspec
に対しtemplatefile関数を使って動的に値を渡します。
data "aws_availability_zones" "available" { state = "available" } resource "eksctl_cluster" "main" { eksctl_version = "0.38.0" name = var.cluster_name region = var.region version = var.k8s_version spec = templatefile( "./modules/k8s_cluster/yaml/eksctl-config.yaml" , { target_group_arn = aws_alb_target_group.tg.arn az = data.aws_availability_zones.available.names private = var.private_subnet_ids public = var.public_subnet_ids } ) vpc_id = var.vpc_id }
VPCのIDについては、素のeksctl(=terraform-provider-eksctlを介さず直接eksctlを使う、という意味です)ではYAMLファイル内(上記spec
引数部分に相当)に指定することができます。が、terraform-provider-eksctlでspec
内に記載したところ、
Error: validating eksctl_cluster's "spec": vpc.id must not be set within the spec yaml. use "vpc_id" attribute instead, becaues the provider uses it for generating the final eksctl cluster config yaml
と怒られましたので、 vpc_id
引数として spec
から外出しにする必要があるようです。
以下は前述のeksctl.tf
から呼ばれているYAMLファイルの部分です。
nodeGroups: - name: ng2 instanceType: m5.large desiredCapacity: 1 targetGroupARNs: - ${target_group_arn} vpc: subnets: private: ${element(az,0)}: id: ${element(private,0)} ${element(az,1)}: id: ${element(private,1)} ${element(az,2)}: id: ${element(private,2)} public: ${element(az,0)}: id: ${element(public,0)} ${element(az,1)}: id: ${element(public,1)} ${element(az,2)}: id: ${element(public,2)}
vpc.subnets
以降の実装はちょっとイマイチだなと自分でも思うのですが、ちょっと他の方法を思いつきませんでした。。nodeGroups.targetGroupARNs
はNodeGroupのAuto Scaling Groupと紐付けるTarget GroupのARNを指定します。今回の要件では不要ですが、次回以降のブログで必要になる予定なので指定しておきます。以下がそのTarget Groupの定義ファイルです。
resource "aws_alb_target_group" "tg" { name = "${var.cluster_name}-tg" port = 30080 protocol = "HTTP" vpc_id = var.vpc_id }
再びterraform init
してterraform apply
します。
Target Groupとクラスターがプロビジョニングできました。
$ terraform state list data.aws_availability_zones.available data.aws_region.current module.blue.data.aws_availability_zones.available module.blue.aws_alb_target_group.tg module.blue.eksctl_cluster.main module.vpc.aws_eip.nat[0] module.vpc.aws_eip.nat[1] module.vpc.aws_eip.nat[2] module.vpc.aws_internet_gateway.this[0] module.vpc.aws_nat_gateway.this[0] module.vpc.aws_nat_gateway.this[1] module.vpc.aws_nat_gateway.this[2] module.vpc.aws_route.private_nat_gateway[0] module.vpc.aws_route.private_nat_gateway[1] module.vpc.aws_route.private_nat_gateway[2] module.vpc.aws_route.public_internet_gateway[0] module.vpc.aws_route_table.private[0] module.vpc.aws_route_table.private[1] module.vpc.aws_route_table.private[2] module.vpc.aws_route_table.public[0] module.vpc.aws_route_table_association.private[0] module.vpc.aws_route_table_association.private[1] module.vpc.aws_route_table_association.private[2] module.vpc.aws_route_table_association.public[0] module.vpc.aws_route_table_association.public[1] module.vpc.aws_route_table_association.public[2] module.vpc.aws_subnet.private[0] module.vpc.aws_subnet.private[1] module.vpc.aws_subnet.private[2] module.vpc.aws_subnet.public[0] module.vpc.aws_subnet.public[1] module.vpc.aws_subnet.public[2] module.vpc.aws_vpc.this[0]
クラスター内のリソースも確認できました。
$ kubectl get all -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system pod/aws-node-cj9bp 1/1 Running 0 94m kube-system pod/coredns-59847d77c8-s47js 1/1 Running 0 113m kube-system pod/coredns-59847d77c8-z2flq 1/1 Running 0 113m kube-system pod/kube-proxy-rv9vs 1/1 Running 0 94m NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE default service/kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 114m kube-system service/kube-dns ClusterIP 172.20.0.10 <none> 53/UDP,53/TCP 113m NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE kube-system daemonset.apps/aws-node 1 1 1 1 1 <none> 113m kube-system daemonset.apps/kube-proxy 1 1 1 1 1 <none> 113m NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE kube-system deployment.apps/coredns 2/2 2 2 113m NAMESPACE NAME DESIRED CURRENT READY AGE kube-system replicaset.apps/coredns-59847d77c8 2 2 2 113m